package Thread;
/**单例模式之懒汉模式:第一次使用的时候创建的线程，可能涉及到多线程的修改*/

class SingletonLazy{
    // 为了杜绝内存可见性问题，加上volatile,更关键的是指令重排序
    // 1.确保每次读取的都是内存
    // 2.关于该变量读取和修改，不会触发重排序
    private static volatile SingletonLazy instance = null;
    private static Object locker = new Object();

    public static SingletonLazy getInstance4() {
        // 要使程序跑的更快：按需加锁，涉及到线程安全加锁（没创建实例时）
        if(instance == null) {  // 没有创建实例，加锁
            synchronized (locker) {
                if(instance == null) {  // 没有创建实例，实例化对象
                    // 实例化对象可能造成指令重排序
                    // 1.申请内存空间
                    // 2.在空间初始化对象
                    // 3.内存空间首地址赋值给引用变量     重排序后可能不是1 2 3顺序执行
                    // 因此可能导致利用未初始化的对象进行操作！！！
                    instance = new SingletonLazy();
                }
            }
        }
        // 创建了实例，直接return
        return instance;
    }

    // 方法加锁
    public synchronized static SingletonLazy getInstance3() {
        if(instance == null) {
            instance = new SingletonLazy();
        }
        return instance;
    }

    // 加锁
    public static SingletonLazy getInstance2() {
        // 解决了线程安全问题：当第一次加锁是，成功，触发阻塞，new一个新的对象，释放锁，第二个线程加锁，if为假
        // 直接return，相当于只读操作，解决了线程安全问题
        // 但是对第二个线程加锁（或称之为每调用一次都加锁），产生锁竞争，那么会相互阻塞，影响执行效率，产生新的问题
        synchronized (locker) {
            if(instance == null) {
                instance = new SingletonLazy();
            }
        }
        return instance;
    }

    public static SingletonLazy getInstance1() {
        // 虽然 赋值 是原子操作，但是判断+赋值操作不是原子的了,可能导致多个线程执行使new多次
        if(instance == null) {
            instance = new SingletonLazy();
        }
        return instance;
    }

    private SingletonLazy(){}

}

public class demo28 {
    public static void main(String[] args) {
        SingletonLazy t1 = SingletonLazy.getInstance1();
        SingletonLazy t2 = SingletonLazy.getInstance1();
    }
}
